package com.ztesoft.book.common.utils.jwt;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.ztesoft.book.common.constant.Constant;
import com.ztesoft.book.common.utils.encrypt.AesEncryptSm4Util;
import com.ztesoft.book.common.utils.exception.ExUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * @Description JWT工具类
 * @Author YangFan
 * @Date 2021-06-22 17:23
 */
@Slf4j
@Component
public class JwtUtil {


    /**
     * 过期时间改为从配置文件获取
     */
    private static String jwtTokenExpireTime;

    /**
     * JWT认证加密私钥(Base64加密)
     */
    private static String encryptJwtKey;

    @Value("${book.time.jwt-token-expire}")
    public void setJwtTokenExpireTime(String jwtTokenExpireTime) {
        setJwtTokenExpireTimeValue(jwtTokenExpireTime);
    }

    public static void setJwtTokenExpireTimeValue(String jwtTokenExpireTime) {
        JwtUtil.jwtTokenExpireTime = jwtTokenExpireTime;
    }

    @Value("${book.key.jwt}")
    public void setEncryptJwtKey(String encryptJwtKey) {
        setEncryptJwtKeyValue(encryptJwtKey);
    }

    public static void setEncryptJwtKeyValue(String encryptJwtKey) {
        JwtUtil.encryptJwtKey = encryptJwtKey;
    }


    /**
     * 方法功能描述:
     * < 校验token是否正确 >
     *
     * @param token 【参数 1 注释说明】
     *
     * @return boolean
     *
     * @author YangFan
     * @date 2021-07-20 15:34
     */
    public static boolean verify(String token) {

        // 帐号加JWT私钥解密
        String secret = getClaim(token, Constant.USERNAME) + AesEncryptSm4Util.desEncrypt(encryptJwtKey);
        Algorithm algorithm = Algorithm.HMAC256(secret);
        JWTVerifier verifier = JWT.require(algorithm)
                .build();
        verifier.verify(token);
        return true;

    }


    /**
     * 方法功能描述:
     * < 获得Token中的信息无需secret解密也能获得 >
     *
     * @param token 【参数 1 注释说明】
     * @param claim 【参数 2 注释说明】
     *
     * @return String
     *
     * @author YangFan
     * @date 2021-07-20 15:35
     */
    public static String getClaim(String token, String claim) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            // 只能输出String类型，如果是其他类型返回null
            return jwt.getClaim(claim)
                    .asString();
        }
        catch (JWTDecodeException e) {
            ExUtil.throwEx(
                    "【解密Token中的公共信息出现JWTDecodeException异常，-----------------无效TOKEN-----------------】:" + e.getMessage());
            return null;
        }
    }


    /**
     * 方法功能描述:
     * < 生成签名 >
     *
     * @param username          【参数 1 注释说明】
     * @param currentTimeMillis 【参数 2 注释说明】
     *
     * @return String                        【返回值 注释说明】
     *
     * @author YangFan
     * @date 2021-06-22 17:23
     */
    public static String sign(String userid, String username, String currentTimeMillis) {

        // 帐号加JWT私钥加密
        String secret = username + AesEncryptSm4Util.desEncrypt(encryptJwtKey);
        // 此处过期时间是以毫秒为单位，所以乘以1000
        Date date = new Date(System.currentTimeMillis() + Long.parseLong(jwtTokenExpireTime) * 1000);
        Algorithm algorithm = Algorithm.HMAC256(secret);
        // 附带account帐号信息
        return JWT.create()
                .withClaim("userid", userid)
                .withClaim("username", username)
                .withClaim("currentTimeMillis", currentTimeMillis)
                .withExpiresAt(date)
                .sign(algorithm);

    }


    public static String signUserExt(
            String userid, String nickname, String logo, String username, String currentTimeMillis) {

        // 帐号加JWT私钥加密
        String secret = username + AesEncryptSm4Util.desEncrypt(encryptJwtKey);
        // 此处过期时间是以毫秒为单位，所以乘以1000
        Date date = new Date(System.currentTimeMillis() + Long.parseLong(jwtTokenExpireTime) * 1000);
        Algorithm algorithm = Algorithm.HMAC256(secret);
        // 昵称和头像非空赋值“”，保证jwt签名键值不会遗漏
        nickname = (nickname == null) ? "" : nickname;
        logo = (logo == null) ? "" : logo;
        // 附带account帐号信息
        return JWT.create()
                .withClaim("userid", userid)
                .withClaim("username", username)
                .withClaim("nickname", nickname)
                .withClaim("logo", logo)
                .withClaim("currentTimeMillis", currentTimeMillis)
                .withExpiresAt(date)
                .sign(algorithm);

    }

    /**
     * 添加用户id
     *
     * @param userId            实际存储的是用户的学号或者openid
     * @param currentTimeMillis
     *
     * @return
     */
    public static String signUserExt(String userId, String currentTimeMillis) {

        return signUserExt(userId, null, null, "", currentTimeMillis);
    }


}
